package bancosys.tec.rtm.diagnostician.rmi;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;

import org.apache.log4j.Logger;

import bancosys.tec.rtm.diagnostician.DiagnosticianCase;
import bancosys.tec.rtm.diagnostician.exception.DiagnosticianException;

/**
 * Classe que inicializa e armazena referencia para o servico RMI do diagnosticador.
 * 
 * @author Evaristo
 * @version $Id:$ <b>Created on: </b> 04/06/2007
 */
public class DiagnosticianRMIHome {

    private DiagnosticianRMIService diagnosticianRMIService;

    private static final Logger LOG = Logger.getLogger(DiagnosticianRMIHome.class);

    /**
     * Inicializa DiagnosticianRMIHome.
     * 
     * @param diagnosticianCase {@link DiagnosticianCase}
     * @param ip {@link String}
     * @param port int
     * @param name String
     * @throws DiagnosticianException e
     */
    public synchronized void initializeDiagnosticianRMIHome(DiagnosticianCase diagnosticianCase, String ip, int port, String name)
            throws DiagnosticianException {
        this.diagnosticianRMIService = new DiagnosticianRMIServiceImpl(diagnosticianCase);
        try {
            LocateRegistry.createRegistry(port);
        } catch (RemoteException e) {
            throw new DiagnosticianException("Erro ao criar registro para porta: " + port, e);
        }
        this.unbindDiagnosticianRMIService(ip, port, name);
        try {
            this.rebindDiagnosticianRMIService(ip, port, name);
        } catch (Throwable e) {
            throw new DiagnosticianException("Erro ao executar rebind do DiagnosticianRMIService. URL: " + this.getURL(ip, port, name), e);
        }
    }

    /**
     * Finaliza
     * 
     * @param ip String
     * @param port int
     * @param name String
     */
    public synchronized void finalizeDiagnosticianRMIHome(String ip, int port, String name) {
        this.unbindDiagnosticianRMIService(ip, port, name);
        this.diagnosticianRMIService = null;
    }

    /**
     * Executa Unbind do DiagnosticianRMIService.
     * 
     * @param ip {@link String}
     * @param port int
     * @param name {@link String}
     */
    private void unbindDiagnosticianRMIService(String ip, int port, String name) {
        try {
            Naming.unbind(this.getURL(ip, port, name));
        } catch (Exception e) {
            LOG.debug("Não foi possivel executar o método unbind do RMI para DiagnosticianRMIService.");
        }

        try {
            UnicastRemoteObject.unexportObject(this.diagnosticianRMIService, true);
        } catch (Exception e) {
            LOG.debug("Não foi possivel executar o método unexportObject do RMI para DiagnosticianRMIService.");
        }
    }

    /**
     * Executa Rebind do DiagnosticianRMIService.
     * 
     * @param ip String
     * @param port int
     * @param name String
     * @throws DiagnosticianException e
     */
    private void rebindDiagnosticianRMIService(String ip, int port, String name) throws DiagnosticianException {
        try {
            UnicastRemoteObject.exportObject(this.diagnosticianRMIService, port);
        } catch (RemoteException e) {
            LOG.debug("Não foi possivel exportar o DiagnosticianRMIService.");
        }

        try {
            Naming.rebind(this.getURL(ip, port, name), this.diagnosticianRMIService);
        } catch (RemoteException e) {
            throw new DiagnosticianException("Erro no rebind do DiagnosticianRMIService", e);
        } catch (MalformedURLException e) {
            throw new DiagnosticianException("Erro no rebind do DiagnosticianRMIService", e);
        }
    }

    /**
     * Retorna o DiagnosticianRMIService local.
     * 
     * @return DiagnosticianRMIService
     */
    public DiagnosticianRMIService getDiagnosticianLocalRMIService() {
        return this.diagnosticianRMIService;
    }

    /**
     * Retorna o DiagnosticianRMIService do ip, porta e nome passado no parâmetro.
     * 
     * @param ip String
     * @param port int
     * @param name String
     * @throws DiagnosticianException e
     * @return {@link DiagnosticianRMIService}
     */
    public DiagnosticianRMIService getDiagnosticianRMIService(String ip, int port, String name) throws DiagnosticianException {
        try {
            return (DiagnosticianRMIService) Naming.lookup(this.getURL(ip, port, name));
        } catch (MalformedURLException e) {
            throw new DiagnosticianException("URL mal formada de RMI para recuperar DiagnosticianRMIService. URL: "
                    + this.getURL(ip, port, name), e);
        } catch (RemoteException e) {
            throw new DiagnosticianException("Erro ao recuperar remotamente DiagnosticianRMIService. URL: " + this.getURL(ip, port, name),
                    e);
        } catch (NotBoundException e) {
            throw new DiagnosticianException("Erro ao recuperar remotamente DiagnosticianRMIService. URL: " + this.getURL(ip, port, name),
                    e);
        }
    }

    /**
     * Retorna a URL do RMI, formada pelo ip, porta e nome passado nos parâmetros.
     * 
     * @param ip String
     * @param port int
     * @param name String
     * @return String
     */
    public String getURL(String ip, int port, String name) {
        return "rmi://" + ip + ":" + port + "/" + name;
    }
}